package com.itlong.cloud.property.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.itlong.cloud.POJO.DTO.property.*;
import com.itlong.cloud.POJO.PO.DeviceBusinessChangeLogPO;
import com.itlong.cloud.POJO.PO.DeviceBusinessElevatorChangeLogPO;
import com.itlong.cloud.POJO.PO.UnitInfoPO;
import com.itlong.cloud.POJO.VO.property.PropertyProjectUnitInfoVO;
import com.itlong.cloud.POJO.VO.property.PropertyProjectUnitSimpleInfoExVO;
import com.itlong.cloud.POJO.VO.property.PropertyProjectUnitSimpleInfoVO;
import com.itlong.cloud.PlatformConstants;
import com.itlong.cloud.constants.RabbitMQConstant;
import com.itlong.cloud.enumerate.CloudElevatorChangeBusinessEnum;
import com.itlong.cloud.enumerate.DataStatusEnum;
import com.itlong.cloud.enumerate.SmartCommunityEnum;
import com.itlong.cloud.property.dao.IPropertyUnitInfoDao;
import com.itlong.cloud.property.service.IPropertyUnitInfoService;
import com.itlong.cloud.rabbitmq.config.MessageSender;
import com.itlong.cloud.utils.data.handler.SqlUtil;
import com.itlong.cloud.utils.node.JsonUtil;
import com.itlong.cloud.utils.page.Page;
import com.itlong.cloud.utils.random.LogicIdUtil;
import com.itlong.cloud.utils.words.NumberHandlerUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;


/**
* <desc>
*       单元信息处理接口实现..
* </desc>
*
* @createDate 2017-09-22
*/
@Service
public class PropertyUnitInfoServiceImpl implements IPropertyUnitInfoService {

    private final IPropertyUnitInfoDao iPropertyUnitInfoDao; //单元信息数据库访问对象


    private final MessageSender messageSender; //RabitMQ发送

    @Autowired
    public PropertyUnitInfoServiceImpl(IPropertyUnitInfoDao iPropertyUnitInfoDao, MessageSender messageSender) {
        this.iPropertyUnitInfoDao = iPropertyUnitInfoDao;
        this.messageSender = messageSender;
    }


    /**
     * <desc>
     *      保存单个单元信息
     * </desc>
     *
     * @param propertyProjectSaveUnitInfoDTO 添加单元信息数据传输对象
     * @return 受影响的行数
     * @author LewisLouis
     * @createDate 2017-09-26
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public Integer saveUnitInfo(PropertyProjectSaveUnitInfoDTO propertyProjectSaveUnitInfoDTO) throws Exception {

        //组装单元信息数据库实体对象
        UnitInfoPO unitInfoPO = getUnitPOBySaveDTO(propertyProjectSaveUnitInfoDTO);

        //将单元信息实体对象保存到数据库
         return iPropertyUnitInfoDao.save(SqlUtil.durableData(unitInfoPO, PlatformConstants.TABLE_SAVE));


    }

    /**
     * <desc>
     *      修改单元信息【根据单元Id（UnitId）】
     * </desc>
     *
     * @param propertyProjectUpdateUnitInfoDTO 修改单元信息数据传输对象
     * @return 受影响的行数
     * @author LouisLewis
     * @createDate 2017-09-30
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public Integer updateUnitInfo(PropertyProjectUpdateUnitInfoDTO propertyProjectUpdateUnitInfoDTO) throws Exception {


        //将单元信息更新到数据库（事务保护）
        int intRes = this.updateUnitInfoToDB(propertyProjectUpdateUnitInfoDTO);

        //进行云对讲信息更新
        if (propertyProjectUpdateUnitInfoDTO.getNeedNotifyIntercom()){
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("projectId",propertyProjectUpdateUnitInfoDTO.getProjectId());
            DeviceBusinessChangeLogPO deviceBusinessChangeLogPO
                    = new DeviceBusinessChangeLogPO(SmartCommunityEnum.PUSH_FULL,jsonObject,propertyProjectUpdateUnitInfoDTO.getProjectId());
            List<DeviceBusinessChangeLogPO> deviceBusinessChangeLogPOS = new ArrayList<>();
            List<DeviceBusinessElevatorChangeLogPO> deviceElevatorChangeLogPOS = new ArrayList<>();
            deviceBusinessChangeLogPOS.add(deviceBusinessChangeLogPO);
            deviceElevatorChangeLogPOS.add(new DeviceBusinessElevatorChangeLogPO(propertyProjectUpdateUnitInfoDTO.getProjectId(),
                    CloudElevatorChangeBusinessEnum.PUSH_ROOM_FULL,jsonObject.toJSONString()));
            JSONObject dataJs = new JSONObject();
            dataJs.put("data",deviceBusinessChangeLogPOS);
            //云对讲业务指令
            messageSender.send(RabbitMQConstant.RABBITMQ_HANDLE_SMART_COMMUNITY_ORDERS_QUEUE,
                    JsonUtil.toJSON(dataJs), RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_ROUTING_KEY);
            //云电梯业务指令
            dataJs.put("data",deviceElevatorChangeLogPOS);
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_HANDLE_CLOUD_ELEVATOR_CHANGE_BUSINESS_QUEUE,
                    JsonUtil.toJSON(dataJs),
                    RabbitMQConstant.RABBITMQ_CLOUD_ELEVATOR_CHANGE_BUSINESS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_CLOUD_ELEVATOR_CHANGE_BUSINESS_ROUTING_KEY);
        }
        return intRes;
    }



    /**
     * <desc>
     *      修改单元信息【根据单元Id（UnitId）】
     * </desc>
     *
     * @param propertyProjectUpdateUnitInfoDTO 修改单元信息数据传输对象
     * @return 受影响的行数
     * @author LouisLewis
     * @createDate 2018-02-25
     */
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public Integer updateUnitInfoToDB(PropertyProjectUpdateUnitInfoDTO propertyProjectUpdateUnitInfoDTO) throws Exception{
        UnitInfoPO unitInfoPO = new UnitInfoPO();
        BeanUtils.copyProperties(propertyProjectUpdateUnitInfoDTO,unitInfoPO);
        unitInfoPO.setProjectId(null); //不允许更新项目编号
        unitInfoPO.setBuildId(null); //不允许更新楼栋Id
        unitInfoPO.setUnitNum(null); //不允许更新单元编号
        unitInfoPO.setCreateTime(null); //不允许更新创建时间
        unitInfoPO.setUpdateTime(new Date());
        int intRes = iPropertyUnitInfoDao.update(SqlUtil.durableData(unitInfoPO, PlatformConstants.TABLE_UPDATE));
        return intRes;
    }



    /**
     * <desc>
     *      逻辑删除单元信息(支持按unitId或buildId进行删除）
     * </desc>
     *
     * @param propertyProjectRemoveUnitInfoDTO 删除单元信息数据传输对象
     * @return 受影响的行数
     * @author LouisLewis
     * @createDate 2017-09-27
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public Integer removeUnitInfo(PropertyProjectRemoveUnitInfoDTO propertyProjectRemoveUnitInfoDTO) throws Exception{

        return iPropertyUnitInfoDao.remove(propertyProjectRemoveUnitInfoDTO);
    }

    /**
     * <desc>
     *      分页查询单元信息.
     * </desc>
     *
     * @param propertyProjectGetUnitInfoDTO 分页查询单元信息数据传输对象
     * @return 分页查询结果对象
     * @author LewisLouis
     * @createDate 2017-09-28
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public Page<PropertyProjectUnitInfoVO> getPage(PropertyProjectGetUnitInfoDTO propertyProjectGetUnitInfoDTO) throws Exception {
        //将DTO转换为Map params
        Map<String, Object> params = SqlUtil.convertBeanToMapParams(propertyProjectGetUnitInfoDTO);
        params.put("projectId",propertyProjectGetUnitInfoDTO.getProjectId());

        Page<PropertyProjectUnitInfoVO> page = new Page<>();
        page.getPage().setPageSize(propertyProjectGetUnitInfoDTO.getPageSize());
        page.getPage().setCurrentPage(propertyProjectGetUnitInfoDTO.getCurrentPage());
        params.put("startSlip",page.getPage().getStartSlip());
        params.put("pageSize",page.getPage().getPageSize());
        //填充返回数据集
        List<PropertyProjectUnitInfoVO> propertyProjectUnitInfoVOS = iPropertyUnitInfoDao.getPageList(params);
        page.setRows(propertyProjectUnitInfoVOS, iPropertyUnitInfoDao.getRecordCount(params));
        return page;
    }

    /**
     * <desc>
     *      获取指定楼栋下的单元简单信息（单元id ,单元名称）列表
     * </desc>
     *
     * @param propertyProjectGetUnitSimpleInfoDTO 查询单元简单信息（单元ID，单元名称）数据传输对象
     * @return 单元简单信息（单元id ,单元名称）列表
     * @author LewisLouis
     * @createDate 2017-09-30
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public Page<PropertyProjectUnitSimpleInfoVO> getPageUnitSimpleInfoList(PropertyProjectGetUnitSimpleInfoDTO propertyProjectGetUnitSimpleInfoDTO) throws Exception {
        //将DTO转换为Map params
        Map<String, Object> params = SqlUtil.convertBeanToMapParams(propertyProjectGetUnitSimpleInfoDTO);
        Page<PropertyProjectUnitSimpleInfoVO> page = new Page<>();
        page.getPage().setPageSize(propertyProjectGetUnitSimpleInfoDTO.getPageSize());
        page.getPage().setCurrentPage(propertyProjectGetUnitSimpleInfoDTO.getCurrentPage());
        params.put("startSlip",page.getPage().getStartSlip());
        params.put("pageSize",page.getPage().getPageSize());
        //填充返回数据集
        List<PropertyProjectUnitSimpleInfoVO> propertyProjectUnitSimpleInfoVOS = iPropertyUnitInfoDao.getPageUnitSimpleInfoList(params);
        page.setRows(propertyProjectUnitSimpleInfoVOS, iPropertyUnitInfoDao.getRecordCount(params));

        return page;
    }

    /**
     * <desc>
     * 分页查询指定楼栋下的单元简单扩展信息（单元id ,单元名称，房间数量）列表
     * </desc>
     *
     * @param propertyProjectGetUnitSimpleInfoDTO 查询单元简单信息（单元ID，单元名称）数据传输对象
     * @return 单元简单扩展信息（单元id ,单元名称）列表
     * @author LewisLouis
     * @createDate 2017-09-30
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public Page<PropertyProjectUnitSimpleInfoExVO> getPageUnitSimpleInfoExList(PropertyProjectGetUnitSimpleInfoDTO propertyProjectGetUnitSimpleInfoDTO) throws Exception {
        //将DTO转换为Map params
        Map<String, Object> params = SqlUtil.convertBeanToMapParams(propertyProjectGetUnitSimpleInfoDTO);
        Page<PropertyProjectUnitSimpleInfoExVO> page = new Page<>();
        page.getPage().setPageSize(propertyProjectGetUnitSimpleInfoDTO.getPageSize());
        page.getPage().setCurrentPage(propertyProjectGetUnitSimpleInfoDTO.getCurrentPage());
        params.put("startSlip",page.getPage().getStartSlip());
        params.put("pageSize",page.getPage().getPageSize());
        //填充返回数据集
        List<PropertyProjectUnitSimpleInfoExVO> propertyProjectUnitSimpleInfoVOS = iPropertyUnitInfoDao.getPageUnitSimpleInfoExList(params);
        page.setRows(propertyProjectUnitSimpleInfoVOS, iPropertyUnitInfoDao.getRecordCount(params));

        return page;
    }

    /**
     * <desc>
     *      精确查询，获取单个单元信息
     * </desc>
     *
     * @param propertyProjectGetUnitInfoDTO 查询单元信息数据传输对象
     * @return 按创建时间降序排列，首个符合查询条件的单元信息
     * @author LouisLewis
     * @createDate 2017-09-29
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public PropertyProjectUnitInfoVO getOneUnitInfo(PropertyProjectGetUnitInfoDTO propertyProjectGetUnitInfoDTO) {
        UnitInfoPO inUnitInfoPO = new UnitInfoPO();
        BeanUtils.copyProperties(propertyProjectGetUnitInfoDTO,inUnitInfoPO);
        return iPropertyUnitInfoDao.getOneUnitInfo(inUnitInfoPO);
    }

    /**
     * <desc>
     *      查询楼栋下的单元id集合
     * <desc/>
     * @param  buildIds 楼栋ID,多个以英文，分隔，如 11111111，22222222
     * @return  该楼栋下所有的单元ID集合
     * @author Biao.R
     * @createDate 2017/12/9
     */
    @Override
    public List<String> getUnitIdInBuildIds(String buildIds) {
        if(StringUtils.isEmpty(buildIds)){
            return null;
        }
        return iPropertyUnitInfoDao.getUnitIdInBuildIds(buildIds);
    }

    /**
     * <desc>
     *      获取最小可用单元代号
     * </desc>
     *
     * @param getMinAvaliableUnitAliasDTO  获取最小可用单元代号的参考信息
     * @return 最小可用单元代号
     * @author LewisLouis
     * @createDate 2018-01-15
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public String getMinAvaliableUnitAlias(PropertyProjectGetMinAvaliableUnitAliasDTO getMinAvaliableUnitAliasDTO) {

        List<String> unitAliasHasUsed = iPropertyUnitInfoDao.getUnitAliasByProjectId(getMinAvaliableUnitAliasDTO.getProjectId());

        //首先按默认规则生成单元代号，若未被使用，则直接返回
        String defaultUnitAlias =  String.format("%s%s",getMinAvaliableUnitAliasDTO.getBuildNum(),getMinAvaliableUnitAliasDTO.getUnitNum());
        defaultUnitAlias = defaultUnitAlias.replaceAll("^(0+)", "");
        int unitAliasIndex = unitAliasHasUsed.indexOf(defaultUnitAlias);
        if (unitAliasIndex < 0){
            return  defaultUnitAlias;
        }

        //再取本楼栋下的可能的单元代号，若未被使用，则直接返回
        for (int oneUnitNum = PlatformConstants.MIN_UNIT_NUM;
             oneUnitNum < PlatformConstants.ONE_BUILD_MAX_UNIT_NUM; oneUnitNum++){
            defaultUnitAlias = String.format("%s%02d",getMinAvaliableUnitAliasDTO.getBuildNum(),oneUnitNum);
            defaultUnitAlias = defaultUnitAlias.replaceAll("^(0+)", "");
            unitAliasIndex = unitAliasHasUsed.indexOf(defaultUnitAlias);
            if (unitAliasIndex < 0){
                return  defaultUnitAlias;
            }
        }

        //最后根据已使用的单元代号获取最小可用的单元代号
        for (int oneUnitAlias = PlatformConstants.MIN_UNIT_ALIAS;
             oneUnitAlias < PlatformConstants.MAX_UNIT_ALIAS; oneUnitAlias++){
            String unitAlias = String.valueOf(oneUnitAlias);
            if (unitAliasHasUsed.indexOf(unitAlias) < 0){
                return unitAlias;
            }
        }
        System.out.println(String.format("未找到可用的单元代号,相关信息:%s", JSON.toJSONString(getMinAvaliableUnitAliasDTO)));
        return defaultUnitAlias;
    }

    /**
     * <desc>
     *      根据楼栋数据库实体对象和单元序号返回默认单元信息数据库实体对象，用于保存到数据库
     * </desc>
     *
     * @param propertyProjectSaveUnitInfoDTO  添加单元信息数据传输对象
     * @return 单元信息数据库实体对象
     * @author LewisLouis
     * @createDate 2017-09-22
     */
    private UnitInfoPO getUnitPOBySaveDTO(PropertyProjectSaveUnitInfoDTO propertyProjectSaveUnitInfoDTO){
        String projectId = propertyProjectSaveUnitInfoDTO.getProjectId();
        String buildId = propertyProjectSaveUnitInfoDTO.getBuildId();

        UnitInfoPO unitInfoPO = new UnitInfoPO();
        BeanUtils.copyProperties(propertyProjectSaveUnitInfoDTO,unitInfoPO);
        if (StringUtils.isBlank(propertyProjectSaveUnitInfoDTO.getUnitNum())){
            String newAvailableUnitNum = getMinAvailableUnitNum(buildId);
            unitInfoPO.setUnitNum(newAvailableUnitNum);
        } else {
            unitInfoPO.setUnitNum(propertyProjectSaveUnitInfoDTO.getUnitNum());
        }
        unitInfoPO.setUnitGroupNum(propertyProjectSaveUnitInfoDTO.getUnitGroupNum());
        unitInfoPO.setStatus(DataStatusEnum.NORMAL.getType());
        Date createTime = new Date();
        unitInfoPO.setCreateTime(createTime);
        unitInfoPO.setUpdateTime(createTime);
        String unitId = LogicIdUtil.bussinessId();
        unitInfoPO.setUnitId(unitId);
        unitInfoPO.setBuildId(buildId);
        unitInfoPO.setProjectId(projectId);
        return unitInfoPO;
    }

    /**
     * <desc>
     *      获取指定楼栋的最小可用单元编号(UnitNum).
     * </desc>
     *
     * @param buildId 指定楼栋Id
     * @return 最小可用单元编号(UnitNum).
     * @author LewisLouis
     * @createDate 2017-09-26
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public String getMinAvailableUnitNum(String buildId)
    {
        //从数据库中查询出所有已使用的单元编号
        List<String> unitNumList = iPropertyUnitInfoDao.getUnitNumList(buildId);
        //初始化为最小单元编号
        String oneUnitNum = NumberHandlerUtil.numFormatToString(PlatformConstants.MIN_UNIT_NUM,2);

        //该楼栋下还未设置单元信息时，直接返回最小单元编号
        if (unitNumList.isEmpty())
        {
            return oneUnitNum;
        }
        //从最小单元编号到最大单元编号,依次遍历,检查楼单元编号是否已使用，若未使用，则直接返回
        for (int unitIndex = PlatformConstants.MIN_UNIT_NUM;
             unitIndex <= PlatformConstants.MAX_UNIT_NUM; unitIndex++ )
        {
            oneUnitNum = NumberHandlerUtil.numFormatToString(unitIndex,2);
            if (!unitNumList.contains(oneUnitNum))
            {
                return oneUnitNum;
            }
        }
        return oneUnitNum;

    }

    /**
     * <desc>
     *      一次性接口，初始化所有单元组号
     * </desc>
     *
     * @throws Exception
     * @author wangzhi
     * @createDate 2018/08/21
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void initializeUnitGroupNum() throws Exception {
        Date nowTime = new Date();
        List<UnitInfoPO> unitInfoPOList = iPropertyUnitInfoDao.getAllUnitInfo();
        if (unitInfoPOList == null || unitInfoPOList.isEmpty()) {
            return;
        }
        Map<String,Integer> unitGroupNumMap = new HashMap<>();
        for (UnitInfoPO unitInfoPO : unitInfoPOList){
            Integer unitGroupNum = unitGroupNumMap.get(unitInfoPO.getProjectId());
            if (unitGroupNum == null) {
                unitGroupNum = 1;
                unitInfoPO.setUnitGroupNum(NumberHandlerUtil.numFormatToString(unitGroupNum,2));
                unitInfoPO.setUpdateTime(nowTime);
                unitGroupNumMap.put(unitInfoPO.getProjectId(),++unitGroupNum);
            } else {
                unitInfoPO.setUnitGroupNum(NumberHandlerUtil.numFormatToString((unitGroupNum % 99) == 0 ? 99 : (unitGroupNum % 99),2));
                unitInfoPO.setUpdateTime(nowTime);
                unitGroupNumMap.put(unitInfoPO.getProjectId(),++unitGroupNum);
            }
        }
        iPropertyUnitInfoDao.updateUnitGroupNum(unitInfoPOList);
    }

    /**
     * <desc>
     *      获取最小可用单元组号
     * </desc>
     *
     * @param projectId 项目id
     * @return 单元组号
     * @author wangzhi
     * @createDate 2018/08/21
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public String getMinAvailableUnitGroupNum(String projectId) throws Exception {
        Integer unitGroupNum = iPropertyUnitInfoDao.getMaxUnitGroupNum(projectId);
        if (unitGroupNum == null) {
            return NumberHandlerUtil.numFormatToString(1,2);
        }
        unitGroupNum += 1;
        if (NumberHandlerUtil.isInRange(unitGroupNum, PlatformConstants.MIN_UNIT_GROUP_NUM, PlatformConstants.MAX_UNIT_GROUP_NUM)) {
            return NumberHandlerUtil.numFormatToString(unitGroupNum,2);
        }
        // 超出99之后，重新从1开始循环
        List<String> list = iPropertyUnitInfoDao.getUnitGroupNumGroupCountMap(projectId);
        Map<String,Integer> map = new HashMap<>();
        for (String str : list){
            String[] split = str.split(",");
            map.put(split[0],new Integer(split[1]));
        }
        // 单元会有删除的情况，会导致项目下单元组号被删的错乱不堪，要从头补起
        for (int i = 2; i <= 99; i++) {
            int ii = map.get(NumberHandlerUtil.numFormatToString(i, 2)) == null ? 0 : map.get(NumberHandlerUtil.numFormatToString(i, 2));
            int iiBefore = map.get(NumberHandlerUtil.numFormatToString((i - 1), 2)) == null ? 0 : map.get(NumberHandlerUtil.numFormatToString((i - 1), 2));
            if (ii < iiBefore) {
                return NumberHandlerUtil.numFormatToString(i,2);
            }
            if (ii > iiBefore) {
                return NumberHandlerUtil.numFormatToString(i - 1,2);
            }
        }
        int i1 = map.get("01") == null ? 0 : map.get("01");
        int i99 = map.get("99") == null ? 0 : map.get("99");
        if (i1 == i99) {
            return NumberHandlerUtil.numFormatToString(1,2);
        }
        return "01";
    }

    /**
     * <desc>
     *      获取项目动态密码验证方式
     * </desc>
     *
     * @param projectId 项目id
     * @return 项目动态密码验证方式
     * @author wangzhi
     * @createDate 2018/08/21
     */
    @Override
    public Integer getProjectOtpOnline(String projectId) {
        return iPropertyUnitInfoDao.getProjectOtpOnline(projectId);
    }
}
